#pragma once

#include <iostream>
#include <string>

struct SharedState {
    std::string m_brand;
    std::string m_model;
    std::string m_color;

    SharedState(const std::string &brand, const std::string &model, const std::string &color)
    {
        this->m_brand = brand;
        this->m_model = model;
        this->m_color = color;
    }

    friend std::ostream &operator<<(std::ostream &os, const SharedState &ss)
    {
        return os << "[ " << ss.m_brand << " , " << ss.m_model << " , " << ss.m_color << " ]";
    }
};

struct UniqueState {
    std::string m_owner;
    std::string m_plates;

    UniqueState(const std::string &owner, const std::string &plates)
    {
        this->m_owner  = owner;
        this->m_plates = plates;
    }

    friend std::ostream &operator<<(std::ostream &os, const UniqueState &us)
    {
        return os << "[ " << us.m_owner << " , " << us.m_plates << " ]";
    }
};

class Flyweight
{
public:
    Flyweight(const SharedState *shared_state)
    {
        m_shared_state = new SharedState(*shared_state);
    }

    Flyweight(const Flyweight &other)
    {
        m_shared_state = new SharedState(*other.m_shared_state);
    }

    ~Flyweight()
    {
        delete m_shared_state;
    }

public:
    SharedState *shared_state() const
    {
        return m_shared_state;
    }

    void operation(const UniqueState &unique_state) const
    {
        std::cout << "Flyweight: Displaying shared (" << *m_shared_state << ") and unique (" << unique_state << ") state." << std::endl;
    }

private:
    SharedState *m_shared_state;
};